/*
 * 在Orchard Core中创建仪表板页面非常简单，只需将控制器命名为AdminController或在控制器上添加[Admin]属性即可。
 * 在本节中，您将学习如何向仪表板添加页面以及如何创建菜单项。
 * 
 * 主要功能：
 * - 提供Orchard Core管理仪表板的页面访问
 * - 展示内容项的列表显示
 * - 演示权限控制和授权机制
 * - 展示如何使用YesSql进行数据查询
 */

using Lombiq.TrainingDemo.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Display;
using OrchardCore.ContentManagement.Records;
using OrchardCore.DisplayManagement;
using OrchardCore.DisplayManagement.ModelBinding;
using System.Collections.Generic;
using System.Threading.Tasks;
using YesSql;

namespace Lombiq.TrainingDemo.Controllers;

/// <summary>
/// 管理控制器 - 提供Orchard Core仪表板页面功能
/// 
/// 主要用途：
/// - 为Orchard Core管理界面提供自定义页面
/// - 展示人员内容项的列表和管理功能
/// - 演示权限控制和数据查询的最佳实践
/// 
/// 使用场景：
/// - 管理员查看最新创建的人员列表
/// - 管理员查看最早创建的人员列表
/// - 展示Orchard Core仪表板集成方式
/// 
/// 设计原因：
/// - 遵循Orchard Core的命名约定，自动集成到管理界面
/// - 提供标准化的内容项显示方式
/// - 演示权限控制在实际应用中的使用
/// 
/// 设计模式：
/// - 依赖注入模式：通过构造函数注入所需服务
/// - 授权模式：使用IAuthorizationService进行权限检查
/// - 查询模式：使用YesSql进行数据查询和排序
/// </summary>
// 如果您有多个管理控制器，可以随意命名但需要在它们上放置[Admin]属性
public sealed class AdminController : Controller
{
    private readonly IContentItemDisplayManager _contentItemDisplayManager;
    private readonly ISession _session;
    private readonly IAuthorizationService _authorizationService;
    private readonly IUpdateModelAccessor _updateModelAccessor;

    /// <summary>
    /// 构造函数 - 注入所需的服务依赖
    /// </summary>
    /// <param name="contentItemDisplayManager">内容项显示管理器，用于构建内容项的显示形状</param>
    /// <param name="session">YesSql会话，用于数据库查询操作</param>
    /// <param name="authorizationService">授权服务，用于权限检查</param>
    /// <param name="updateModelAccessor">模型更新访问器，用于模型绑定</param>
    public AdminController(
        IContentItemDisplayManager contentItemDisplayManager,
        ISession session,
        IAuthorizationService authorizationService,
        IUpdateModelAccessor updateModelAccessor)
    {
        _contentItemDisplayManager = contentItemDisplayManager;
        _session = session;
        _authorizationService = authorizationService;
        _updateModelAccessor = updateModelAccessor;
    }

    /// <summary>
    /// 默认索引页面
    /// 
    /// 功能说明：
    /// - 提供管理界面的默认入口页面
    /// - 自动进行权限检查（需要AccessAdmin权限）
    /// - 匿名用户会自动跳转到登录页面
    /// 
    /// 访问方式：
    /// - 默认URL：/Lombiq.TrainingDemo/Admin/Index
    /// - 需要管理员账户或具有AccessAdmin权限的角色
    /// </summary>
    /// <returns>返回默认视图</returns>
    public IActionResult Index() => View();

    /// <summary>
    /// 获取最新创建的人员列表
    /// 
    /// 功能说明：
    /// - 查询最近创建的10个PersonPage内容项
    /// - 按创建时间降序排列
    /// - 进行权限检查确保用户有访问权限
    /// 
    /// 权限要求：
    /// - 需要AccessPersonListDashboard权限
    /// - 无权限时返回401未授权状态
    /// 
    /// 数据查询：
    /// - 使用YesSql查询ContentItemIndex
    /// - 过滤PersonPage内容类型
    /// - 按CreatedUtc降序排序
    /// </summary>
    /// <returns>返回人员列表视图</returns>
    // 您不必通过输入URL来访问下面的两个操作，因为我们为它们创建了管理菜单项！
    // 下一站：Navigation/PersonsAdminMenu.cs
    public async Task<IActionResult> PersonListNewest()
    {
        // 如果用户需要在管理面板上访问页面时具有特定权限（除了AccessAdmin权限），
        // 您需要在这里检查它。
        if (!await _authorizationService.AuthorizeAsync(User, PersonPermissions.AccessPersonListDashboard))
        {
            return Unauthorized();
        }

        // 这里没有什么特别的，只是显示最后10个Person Page内容项。
        var persons = await _session
            .Query<ContentItem, ContentItemIndex>()
            .Where(index => index.ContentType == ContentTypes.PersonPage)
            .OrderByDescending(index => index.CreatedUtc)
            .Take(10)
            .ListAsync();

        // 在Views/Admin/PersonList.cshtml文件中，您可以看到如何显示形状列表（IEnumerable<dynamic>）。
        return View("PersonList", await GetShapesAsync(persons));
    }

    /// <summary>
    /// 获取最早创建的人员列表
    /// 
    /// 功能说明：
    /// - 查询最早创建的10个PersonPage内容项
    /// - 按创建时间升序排列
    /// - 进行权限检查确保用户有访问权限
    /// 
    /// 权限要求：
    /// - 需要AccessPersonListDashboard权限
    /// - 无权限时返回401未授权状态
    /// 
    /// 数据查询：
    /// - 使用YesSql查询ContentItemIndex
    /// - 过滤PersonPage内容类型
    /// - 按CreatedUtc升序排序
    /// </summary>
    /// <returns>返回人员列表视图</returns>
    public async Task<IActionResult> PersonListOldest()
    {
        if (!await _authorizationService.AuthorizeAsync(User, PersonPermissions.AccessPersonListDashboard))
        {
            return Unauthorized();
        }

        // 显示前10个Person Page内容项。
        var persons = await _session
            .Query<ContentItem, ContentItemIndex>()
            .Where(index => index.ContentType == ContentTypes.PersonPage)
            .OrderBy(index => index.CreatedUtc)
            .Take(10)
            .ListAsync();

        return View("PersonList", await GetShapesAsync(persons));
    }

    /// <summary>
    /// 将内容项转换为显示形状
    /// 
    /// 功能说明：
    /// - 为每个人员内容项构建显示形状
    /// - 使用"SummaryAdmin"显示类型，这是专门为仪表板列表项设计的内置显示类型
    /// - 支持异步处理多个内容项
    /// 
    /// 参数说明：
    /// - persons：要转换的人员内容项集合
    /// 
    /// 返回值：
    /// - 返回形状集合，用于在视图中显示
    /// </summary>
    /// <param name="persons">人员内容项集合</param>
    /// <returns>显示形状集合</returns>
    private async Task<IEnumerable<IShape>> GetShapesAsync(IEnumerable<ContentItem> persons) =>
        // 注意"SummaryAdmin"显示类型，这是专门为在仪表板上列出项目而设计的内置显示类型。
        await persons.AwaitEachAsync(async person =>
            await _contentItemDisplayManager.BuildDisplayAsync(person, _updateModelAccessor.ModelUpdater, "SummaryAdmin"));
}

// 下一站：Navigation/TrainingDemoNavigationProvider.cs
